package com.coder4j.config;


import com.alibaba.fastjson.JSON;
import com.coder4j.annotation.OperationLog;
import com.coder4j.enums.StatusEnums;
import com.coder4j.starter.web.R;
import com.coder4j.utils.RequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

/**
 * 使用 AOP 实现 Controller 日志的打印
 *
 * @author Keller
 * @date 2022-08-04 10:17:02
 */
@Aspect
@Component
@Slf4j
public class ControllerLogAspect {

    /**
     * 切点定在项目中所有controller层的方法上
     */
    @Pointcut("execution(* *..*Controller.*(..))")
    public void controllerLog() {
    }

    @AfterReturning(pointcut = "controllerLog()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null) {
            return;
        }
        boolean saveLogFlag = false;

        //如果方法上有@OperationLog注解，日志入库
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        OperationLog operationLog = method.getAnnotation(OperationLog.class);
        if (operationLog != null) {
            saveLogFlag = true;
        }

        //解析Request
        HttpServletRequest request = requestAttributes.getRequest();
        //解析RequestBody,仅解析JSON格式的Body
        String contentType = request.getContentType();

        log.info("===>Request,url:{},params:{}", request.getRequestURI() ,this.getRequestParam(request));
        log.info("===>Request body{}", this.getRequestBody(contentType, joinPoint));

        log.info("===>Response,{}", JSON.toJSONString(result));

    }


    /**
     * 获取请求体
     *
     * @param contentType
     * @param joinPoint
     * @return
     */
    private String getRequestBody(String contentType, JoinPoint joinPoint) {
        try {
            Object[] args = joinPoint.getArgs();
            if (args == null || args.length == 0) {
                return null;
            }
            for (Object arg : args) {
                if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                    continue;
                }
                //打印json参数
                if (contentType != null && contentType.startsWith(MediaType.APPLICATION_JSON_VALUE)) {
                    return JSON.toJSONString(arg);
                }
            }
            return null;
        }catch (Exception e){

        }
        return null;
    }

    /**
     * 获取请求参数
     *
     * @param request
     * @return
     */
    private String getRequestParam(HttpServletRequest request) {
        Map<String, String[]> parameterMap = request.getParameterMap();
        if (parameterMap.isEmpty()) {
            return null;
        }
        StringBuilder param = new StringBuilder();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            param.append(entry.getKey()).append(":").append(Arrays.toString(entry.getValue())).append("\n");
        }
        return param.toString();
    }

}
